from django.shortcuts import render

# Create your views here.
"""
先实现功能再优化
１．登录用户的购物车保存在服务器，未登录用户保存在cookie中
２．我们需要保存商品的id,个数和选中的状态
３．cookie的保存格式：{sku_id:{count:5,selected:True}}
服务器(数据库/Redis)的保存格式:Redis中内存，
使用redis原则：尽量少的空间来实现功能
sku_id,count,selected
Hash:
cart_6:
    {sku_id:count}
    .
    .
    .
记录选中的id,没有在列表中的自然就是没有选中的
cart_8
(sku_id,sku_id...)
"""
from rest_framework.views import APIView
from django_redis import get_redis_connection
import base64
import pickle
from rest_framework.response import Response
from .serializers import CartSerializer, CartSKUSerializer,CartDeleteSerializer
from goods.models import SKU
from rest_framework import status

class CartView(APIView):
    def perform_authentication(self, request):
        # 用户在进行提交购物车的时候，会进行token验证，如果用户伪造token或者token过期了则不能进行购物车的添加
        # 我们先将token的认证关掉
        pass

    def post(self, request):
        """
        1.前端应该把sku_id,count必须传递过来，是否选中的状态是一个可选
        2.我们需要对前端提交的数据进行校验
        3.检验完成后，我们需要得到数据，然后将数据保存在指定的地方
        4.获取登陆的状态
        5.登陆用户保存在redis中
        6.未登录用户保存在cookie中
        """
        serializer = CartSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        sku_id = serializer.data.get("sku_id")
        count = serializer.validated_data.get('count')
        selected = serializer.validated_data.get("selected")

        try:
            user = request.user
        except Exception:
            user = None

        # print(user)
        # request.user.is_authenticated
        if user is not None and user.is_authenticated:
            # 登陆用户，保存在redis中
            redis_conn = get_redis_connection('cart')

            # # 添加redis商品id和数量
            # redis_conn.hincrby("cart_%s" % user.id, sku_id, count)
            # # 添加商品的选中信息
            # if selected:
            #     redis_conn.sadd('cart_selected_%s' % user.id, sku_id)
            p1 = redis_conn.pipeline()
            p1.hincrby("cart_%s" % user.id, sku_id, count)
            if selected:
                p1.sadd('cart_selected_%s' % user.id, sku_id)

            p1.execute()
            return Response(serializer.data)

        else:
            # 未登陆用户
            cookie_str = request.COOKIES.get('cart')
            if cookie_str is not None:
                # 如果数据存在就需要解码
                decode = base64.b64decode(cookie_str)
                cart = pickle.loads(decode)

            else:
                cart = {}
            # 如果之前添加过对应的商品，应该对数量进行累加
            if sku_id in cart:
                orginal_count = cart[sku_id]['count']
                count += orginal_count

            # 更新数据
            cart[sku_id] = {
                'count': count,
                'selected': selected
            }
            # 对最终的购物车数据进行编码
            dumps = pickle.dumps(cart)

            encode = base64.b64encode(dumps)

            value = encode.decode()

            # 设置cookie
            response = Response(serializer.data)
            response.set_cookie('cart', value, 3600 * 24)
            return response

    def get(self, request):
        """
            1.判断用户的登陆状态
            2.如果是登陆用户，则根据redis获取数据
            3.如果是未登陆用户则根据cookie获取数据
            4.根据sku_id获取商品的详细信息
            5.将商品的信息通过序列化器转化为字典
        """
        # 1.判断用户的登陆状态
        try:
            user = request.user
        except Exception:
            user = None
        if user is not None and user.is_authenticated:
            # 2.如果是登陆用户，则根据redis获取数据
            # 2.1获取商品redis中的hash值
            redis_conn = get_redis_connection('cart')
            redis_cart = redis_conn.hgetall('cart_%s' % user.id)
            # 2.2获取选中的商品id
            redis_selected_ids = redis_conn.smembers('cart_selected_%s' % user.id)
            # 将redis数据统一为cart数据格式
            cart = {}
            for sku_id, count in redis_cart.items():
                cart[sku_id.decode()] = {
                    'count': int(count),
                    'selected': sku_id in redis_selected_ids
                }
        else:
            # 3.如果是未登陆用户则根据cookie获取数据
            cookie_str = request.COOKIES.get('cart')
            if cookie_str is not None:
                # 如果cookie存在则对cookie数据进行解析
                decode = base64.b64decode(cookie_str)
                cart = pickle.loads(decode)
            else:
                # 如果cookie不存在则返回空字典
                cart = {}
        # 4.根据sku_id获取商品的详细信息
        ids = cart.keys()
        skus = SKU.objects.filter(pk__in=ids)
        for sku in skus:
            sku.count = cart[str(sku.id)]['count']
            sku.selected = cart[str(sku.id)]['selected']
        # 5.将商品的信息通过序列化器转化为字典
        serializer = CartSKUSerializer(skus, many=True)

        return Response(serializer.data)

    def put(self, request):
        """
        只要修改，就把所有的数据都提交，无论是只改数量还是只改是否选中
        幂等，就是将最终的结果交给后端，也得把最终结果返回给前端
        分析：
        １.前端应该把sku_id,count必须传递过来，是否选中的状态是一个可选
        ２.我们需要对前端提交的数据进行校验
        ３.校验完成后需要把数据保存在指定的地方
        ４.获取用户登陆的状态
        ５.登录用户保存在redis中
        ６.未登录用户保存在cookie中
        """
        # １.前端应该把sku_id, count必须传递过来，是否选中的状态是一个可选
        data = request.data
        # ２.我们需要对前端提交的数据进行校验
        serializer = CartSerializer(data=data)
        serializer.is_valid(raise_exception=True)
        # 校验完成后获取数据
        sku_id = serializer.data.get('sku_id')
        count = serializer.data.get('count')
        selected = serializer.data.get('selected')
        # ３.校验完成后需要把数据保存在指定的地方
        # ４.获取用户登陆的状态
        try:
            user = request.user
        except Exception:
            user = None
        if user is not None and user.is_authenticated:
            # ５.登录用户保存在redis中
            redis_conn = get_redis_connection('cart')
            # 保存hash数据
            redis_conn.hset('cart_%s' % user.id, sku_id, count)
            # 保存用户选中的商品id,
            if selected:
                # 如果用户点击选中，则在redis中的集合添加数据
                redis_conn.sadd('cart_selected_%s' % user.id, sku_id)
            else:
                # 如果用户点击的是未选中，则直接把集合中的sku_id删除
                redis_conn.srem('cart_selected_%s' % user.id, sku_id)
            return Response(serializer.data)
        else:
            # ６.未登录用户保存在cookie中
            # 获取cookie信息，并进行判断
            cookie_str = request.COOKIES.get('cart')
            if cookie_str is not None:
                # 如果cookie存在，则对cookie进行解析
                cart = pickle.loads(base64.b64decode(cookie_str))
            else:
                # 如果cookie不存在则返回空字典
                cart = {}

            # ７对数据进行更新，首先需要判断商品信息是否在购物车，如果存在则跟新，不存在则创建，创建是在post方法中完成的
            if sku_id in cart:
                cart[str(sku_id)] = {
                    'count': count,
                    'selected': selected
                }
            # ８．将更新好的数据进行加密并返回给前端
            value = base64.b64encode(pickle.dumps(cart)).decode()
            # 设置cookie
            response = Response(serializer.data)
            response.set_cookie('cart', value, 3600 * 24)

            return response

    def delete(self, request):
        """
        １．前端应该把sku_id传递过来
        ２．我们需要对前端的数据进行校验
        ３．校验完成后，需要得到数据，然后将数据到指定的地方删除
        ４．获取登录的状态
        ５．如果时登陆用户保存在redis中
        ６．如果是未登陆用户保存在cookie中
        """
        # １．前端应该把sku_id传递过来
        data = request.data
        serializer = CartDeleteSerializer(data=data)
        # ２．我们需要对前端的数据进行校验
        serializer.is_valid(raise_exception=True)
        # ３．校验完成后，需要得到数据，然后将数据到指定的地方删除
        sku_id = serializer.data.get('sku_id')
        # ４．获取登录的状态ry
        try:
            user = request.user
        except Exception:
            user = None

        if user is not None and user.is_authenticated:
            # ５．如果时登陆用户在redis中删除数据
            redis_conn = get_redis_connection('cart')
            # 删除hasi数据
            redis_conn.hdel('cart_%s'%user.id,sku_id)
            # 删除选中的商品信息
            redis_conn.srem('cart_selected_%s'%user.id,sku_id)

            return Response(status=status.HTTP_204_NO_CONTENT)
        else:
            # ６．如果是未登陆用户在cookie中删除数据
            # 获取cookie数据
            cookie_str = request.COOKIES.get('cart')
            # 对cookie数据进行判断
            if cookie_str is not None:
                # 如果cookie存在则对其解析
                cart = pickle.loads(base64.b64decode(cookie_str))
            else:
                # 如果不存在则返回空字典
                cart = {}
            response = Response(status=status.HTTP_204_NO_CONTENT)
            # 如果商品信息在购物车中，则对其进行删除
            if sku_id in cart:
                del cart[sku_id]

            value = base64.b64encode(pickle.dumps(cart)).decode()
            # 把商品信息重新设置到cookie中
            response.set_cookie('cart',value,3600*24)

            return response

